package com.hzw.saas.common.storage.service.impl;

import cn.hutool.core.util.StrUtil;
import com.hzw.saas.common.config.util.AssertUtil;
import com.hzw.saas.common.storage.service.IS3FileService;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.util.List;

/**
 * <p>
 * 抽象S3，使得其支持对目录的操作
 * </p>
 *
 * @author sonam
 * @since 2021/1/29 16:44
 */
@Slf4j
public abstract class AbstractS3FileServiceImpl implements IS3FileService {

    public abstract void initOssClient();

    protected abstract void copyFile(String key, String newKey);

    protected abstract String getStorageName();

    @Override
    public void rename(String srcPath, String targetName) throws IOException {
        log.debug(String.format("[%s]重命名>>>>[%s]", srcPath, targetName));
        if (srcPath.endsWith(targetName)) {
            // do nothing
            return;
        }
        AssertUtil.assertThrow("重命名失败,请设置正确的目录名称",
            targetName.contains(StrUtil.SLASH)
                || targetName.contains("*") || targetName.contains("|")
                || targetName.contains("{") || targetName.contains("}")
                || targetName.contains("<") || targetName.contains(">")
                || targetName.contains("@") || targetName.contains("#")
                || targetName.contains("$") || targetName.contains("%"));
        if (!srcPath.endsWith("/")) {
            /** 文件*/
            AssertUtil.assertThrow("重命名失败,重命名的文件不存在", !exists(srcPath));
            String newFileKey = getFileKeyParent(srcPath) + targetName;
            AssertUtil.assertThrow(String.format("重命名失败,文件[%s]已存在", newFileKey), exists(newFileKey));
            copyFile(srcPath, newFileKey);
        } else {
            /** 1、创建重命名的目录 */
            String targetDir = getFileKeyParent(srcPath) + targetName;
            createDir(targetDir);
            /** 2、获取原目录文件列表(不包括目录)*/
            List<String> keys = getAllFileByDir(srcPath);
            /** 3、复制所有文件到重命名目录中*/
            for (String key : keys) {
                String childPath = key.substring(key.indexOf(srcPath) + srcPath.length());
                String newKey = targetDir + StrUtil.SLASH + childPath;
                copyFile(key, newKey);
            }
            /** 4、删除父目录里的文件*/
            deleteFiles(keys);
        }
        /** finally 删除父目录*/
        deleteFile(srcPath);
        log.debug(String.format("目录[%s]重命名成功>>>>>[%s]", srcPath, targetName));
    }

    @Override
    public void mv(String srcPath, String targetPath) throws IOException {
        /**  处理目标目录*/
        targetPath = dealDir(targetPath);
        log.debug(String.format("移动[%s]>>>>>[%s]", srcPath, targetPath));

        if (StrUtil.equals(targetPath, "") || StrUtil.equals(targetPath, "/")) { /** 如果目标路径是更路径 */
            targetPath = "";
        } else {
            /** 创建目标目录（每一层都要创建）*/
            String tmpPath = targetPath;
            do {
                createDir(tmpPath);
                tmpPath = getFileKeyParent(tmpPath);
            } while (StringUtil.isNotBlank(tmpPath));
        }

        if (srcPath.endsWith(StrUtil.SLASH)) { // 目录
            AssertUtil.assertThrow("移动失败，不能移动到自己的子目录下", targetPath.startsWith(srcPath));
            AssertUtil.assertThrow(String.format("移动失败，移动的目录[%s]不存在", srcPath), !exists(srcPath));
            List<String> keys = getAllFileByDir(srcPath);
            String finalSrcPath = srcPath.substring(0, srcPath.length() - 1);
            int index = finalSrcPath.lastIndexOf("/");
            if (index != -1) {
                finalSrcPath = finalSrcPath.substring(index);
            }
            /** 资源移动到目标父目录*/
            finalSrcPath = targetPath + dealDir(finalSrcPath);
            AssertUtil.assertThrow(String.format("移动失败,目标目录[%s]存在,请重新设置移动目录", finalSrcPath), exists(finalSrcPath));
            createDir(finalSrcPath);
            for (String key : keys) {
                String childPath = key.substring(key.indexOf(srcPath) + srcPath.length());
                childPath = finalSrcPath + childPath;
                copyFile(key, childPath);
            }
            log.debug(String.format("移动目录[%s]>>>>>[%s]完成", srcPath, targetPath));
            deleteFiles(keys);
        } else { // 文件
            AssertUtil.assertThrow("移动失败，移动的文件不存在", !exists(srcPath));
            String newKey = getFileKeyName(srcPath);
            newKey = targetPath + newKey;
            AssertUtil.assertThrow(String.format("移动文件失败, [%s]已存在", newKey), exists(newKey));
            copyFile(srcPath, newKey);
            log.debug(String.format("移动文件[%s]>>>>>[%s]完成", srcPath, newKey));
        }
        deleteFile(srcPath);
    }

    protected String dealDir(String dir) {
        AssertUtil.assertThrow("目录名称不能为空", StringUtil.isEmpty(dir));
        if (dir.startsWith(StrUtil.SLASH)) {
            dir = dir.substring(1);
        }
        if (dir.endsWith(StrUtil.SLASH)) {
            return dir;
        }
        return dir + StrUtil.SLASH;
    }

    private String getFileKeyParent(String fileKey) {
        String newFileKey = "";
        if (fileKey.endsWith(StrUtil.SLASH)) {
            // 目录
            newFileKey = fileKey.substring(0, fileKey.length() - 1);
            return getFileKeyParent(newFileKey);
        }
        int index = fileKey.lastIndexOf(StrUtil.SLASH);
        if (index != -1) {
            newFileKey = fileKey.substring(0, index + 1);
        }
        return newFileKey;
    }

    private String getFileKeyName(String fileKey) {
        boolean flag = false;
        String fileKeyName = fileKey;
        if (fileKey.endsWith(StrUtil.SLASH)) {
            // 目录
            fileKeyName = fileKey.substring(0, fileKey.length() - 1);
            flag = true;
        }
        int index = fileKeyName.lastIndexOf(StrUtil.SLASH);
        if (index != -1) {
            fileKeyName = fileKeyName.substring(index + 1);
        }
        return flag ? fileKeyName + StrUtil.SLASH : fileKeyName;
    }

}
